package com.dylan.channel.v9.channel;

import com.dylan.channel.v9.EventLoop;
import com.dylan.channel.v9.attribute.DefaultAttributeMap;
import com.dylan.channel.v9.future.ChannelFuture;
import com.dylan.channel.v9.future.ChannelPromise;

import java.net.SocketAddress;

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    private volatile EventLoop eventLoop;
    /**
     * 如果是服务端channel则parent为null
     */
    private final Channel parent;

    /**
     * @Author: PP-jessica
     * @Description:加入unsafe属性了
     */
    private final Unsafe unsafe;
    /**
     * 是否注册完成
     */
    private volatile boolean registered;

    protected AbstractChannel(Channel parent) {
        unsafe = newUnsafe();
        this.parent = parent;
    }

    @Override
    public Unsafe unsafe() {
        return unsafe;
    }

    protected abstract AbstractUnsafe newUnsafe();

    @Override
    public EventLoop eventLoop() {
        EventLoop eventLoop = this.eventLoop;
        if (eventLoop == null) {
            throw new IllegalStateException("channel not registered to an event loop");
        }
        return eventLoop;
    }

    @Override
    public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
        unsafe.connect(remoteAddress, localAddress, promise);
        return promise;
    }

    @Override
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        unsafe.bind(localAddress, promise);
        return promise;
    }

    @Override
    public boolean isRegistered() {
        return registered;
    }

    @Override
    public ChannelFuture newFailedFuture(Throwable cause) {
        return null;
    }

    @Override
    public ChannelFuture newSucceededFuture() {
        return null;
    }

    @Override
    public ChannelPromise newPromise() {
        return null;
    }

    @Override
    public void beginRead() {
        doBeginRead();
    }

    protected abstract void doBeginRead();

    @Override
    public Channel read() {
        unsafe.beginRead();
        return this;
    }
    protected void doRegister() throws Exception {
    }

    protected abstract void doBind(SocketAddress localAddress) throws Exception;

    protected abstract class AbstractUnsafe implements Unsafe {
        private void assertEventLoop() {
            assert !registered || eventLoop.inEventLoop(Thread.currentThread());
        }

        @Override
        public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            try {
                doBind(localAddress);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public final void beginRead() {
            assertEventLoop();
            //如果是服务端的channel，这里仍然可能为false
            //那么真正注册读事件的时机，就成了绑定端口号成功之后
//            if (!isActive()) {
//                return;
//            }
            try {
                doBeginRead();
            } catch (final Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }


        private void register0(ChannelPromise promise) {
            try {
                //开始执行真正得注册逻辑
                doRegister();

                registered = true;

                //开始注册自己感兴趣得事件
                beginRead();

                //将异步结果设置成成功
                promise.setSuccess();
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }

        @Override
        public void register(EventLoop eventLoop, ChannelPromise promise) {
            //断言eventLoop是否为空
            assert eventLoop != null;

            //断言未注册过
            assert !isRegistered();
            //稍微学过netty的人都知道，一个channel绑定一个单线程执行器。终于在这里，我们看到channel绑定了单线程执行器
            //接着channel，不管是客户端还是服务端的，会把自己注册到绑定的单线程执行器中的selector上
            AbstractChannel.this.eventLoop = eventLoop;
            if (eventLoop.inEventLoop(Thread.currentThread())) {
                register0(promise);
            } else {
                eventLoop.execute(new Runnable() {
                    @Override
                    public void run() {
                        register0(promise);
                    }
                });
            }
        }
    }
}
